package mqtt

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"sync"
	"time"

	paho "github.com/eclipse/paho.mqtt.golang"
)

// DeviceInfo 结构体表示设备信息
type DeviceInfo struct {
	DeviceID   string                 `json:"device_id"`
	DeviceType string                 `json:"device_type"`
	Status     string                 `json:"status"` // online, offline
	Properties map[string]interface{} `json:"properties"`
	LastSeen   time.Time              `json:"last_seen"`
}

// MessageHandler 定义消息处理函数类型
type MessageHandler func(topic string, payload []byte)

// SouthboundService 结构体表示南向服务
type SouthboundService struct {
	mqttClient   *MqttClient
	devices      map[string]*DeviceInfo
	devicesLock  sync.RWMutex
	handlers     map[string][]MessageHandler
	handlersLock sync.RWMutex
}

// NewSouthboundService 创建一个新的南向服务实例
func NewSouthboundService(brokerAddr string) *SouthboundService {
	return &SouthboundService{
		mqttClient: NewMqttClient(brokerAddr, "iot-gateway"),
		devices:    make(map[string]*DeviceInfo),
		handlers:   make(map[string][]MessageHandler),
	}
}

// Start 启动南向服务
func (s *SouthboundService) Start() error {
	// 连接到MQTT代理服务器
	if err := s.mqttClient.Connect(); err != nil {
		return fmt.Errorf("failed to connect to MQTT broker: %v", err)
	}

	// 订阅设备相关的主题
	s.subscribeToDeviceTopics()

	log.Println("IoT southbound service started")
	return nil
}

// Stop 停止南向服务
func (s *SouthboundService) Stop() error {
	if s.mqttClient != nil {
		s.mqttClient.Disconnect(250)
	}

	log.Println("IoT southbound service stopped")
	return nil
}

// mqttMessageHandler 转换MQTT消息处理函数格式
func (s *SouthboundService) mqttMessageHandler(handler MessageHandler) paho.MessageHandler {
	return func(client paho.Client, msg paho.Message) {
		handler(msg.Topic(), msg.Payload())
	}
}

// subscribeToDeviceTopics 订阅设备相关的主题
func (s *SouthboundService) subscribeToDeviceTopics() {
	// 订阅设备上线主题
	s.mqttClient.Subscribe("devices/+/connect", 1, s.mqttMessageHandler(s.HandleDeviceConnect))

	// 订阅设备下线主题
	s.mqttClient.Subscribe("devices/+/disconnect", 1, s.mqttMessageHandler(s.HandleDeviceDisconnect))

	// 订阅设备上报数据主题
	s.mqttClient.Subscribe("devices/+/data", 1, s.mqttMessageHandler(s.HandleDeviceData))

	// 订阅设备响应主题
	s.mqttClient.Subscribe("devices/+/response", 1, s.mqttMessageHandler(s.handleDeviceResponse))
}

// handleDeviceConnect 处理设备连接事件
func (s *SouthboundService) HandleDeviceConnect(topic string, payload []byte) {
	// 解析设备ID（从主题中提取）
	deviceID := extractDeviceID(topic)

	s.devicesLock.Lock()
	s.devices[deviceID] = &DeviceInfo{
		DeviceID:   deviceID,
		Status:     "online",
		Properties: make(map[string]interface{}),
		LastSeen:   time.Now(),
	}
	s.devicesLock.Unlock()

	log.Printf("Device connected: %s\n", deviceID)
}

// handleDeviceDisconnect 处理设备断开连接事件
func (s *SouthboundService) HandleDeviceDisconnect(topic string, payload []byte) {
	deviceID := extractDeviceID(topic)

	s.devicesLock.Lock()
	if device, exists := s.devices[deviceID]; exists {
		device.Status = "offline"
		device.LastSeen = time.Now()
	}
	s.devicesLock.Unlock()

	log.Printf("Device disconnected: %s\n", deviceID)
}

// handleDeviceData 处理设备上报的数据
func (s *SouthboundService) HandleDeviceData(topic string, payload []byte) {
	deviceID := extractDeviceID(topic)

	// 解析payload数据
	var data map[string]interface{}
	if err := json.Unmarshal(payload, &data); err != nil {
		log.Printf("Failed to parse device data: %v\n", err)
		return
	}

	// 更新设备属性
	s.devicesLock.Lock()
	if device, exists := s.devices[deviceID]; exists {
		device.LastSeen = time.Now()
		for k, v := range data {
			device.Properties[k] = v
		}
	}
	s.devicesLock.Unlock()

	// 触发注册的处理函数
	s.triggerHandlers(topic, payload)

	log.Printf("Received data from device %s: %v\n", deviceID, data)
}

// handleDeviceResponse 处理设备响应
func (s *SouthboundService) handleDeviceResponse(topic string, payload []byte) {
	deviceID := extractDeviceID(topic)
	log.Printf("Received response from device %s: %s\n", deviceID, payload)

	// 触发注册的处理函数
	s.triggerHandlers(topic, payload)
}

// extractDeviceID 从主题中提取设备ID
func extractDeviceID(topic string) string {
	// 简单的提取逻辑，实际应用中可能需要更复杂的解析
	// 假设主题格式为 "devices/{deviceID}/..."
	var deviceID string
	split := strings.Split(topic, "/")
	if len(split) >= 2 {
		deviceID = split[1]
	}
	return deviceID
}

// RegisterHandler 注册消息处理函数
func (s *SouthboundService) RegisterHandler(topic string, handler MessageHandler) {
	s.handlersLock.Lock()
	s.handlers[topic] = append(s.handlers[topic], handler)
	s.handlersLock.Unlock()
}

// triggerHandlers 触发注册的处理函数
func (s *SouthboundService) triggerHandlers(topic string, payload []byte) {
	s.handlersLock.RLock()
	handlers := s.handlers[topic]
	s.handlersLock.RUnlock()

	for _, handler := range handlers {
		go handler(topic, payload)
	}
}

// SendCommand 向设备发送命令
func (s *SouthboundService) SendCommand(deviceID string, command string, params map[string]interface{}) error {
	// 构建命令消息
	cmd := map[string]interface{}{
		"command":   command,
		"params":    params,
		"timestamp": time.Now().Unix(),
	}

	// 转换为JSON
	payload, err := json.Marshal(cmd)
	if err != nil {
		return fmt.Errorf("failed to marshal command: %v", err)
	}

	// 发送命令到设备的命令主题
	cmdTopic := fmt.Sprintf("devices/%s/commands", deviceID)
	if err := s.mqttClient.Publish(cmdTopic, 1, false, payload); err != nil {
		return fmt.Errorf("failed to publish command: %v", err)
	}

	log.Printf("Sent command to device %s: %s\n", deviceID, payload)
	return nil
}

// GetDeviceStatus 获取设备状态
func (s *SouthboundService) GetDeviceStatus(deviceID string) (string, bool) {
	s.devicesLock.RLock()
	device, exists := s.devices[deviceID]
	s.devicesLock.RUnlock()

	if !exists {
		return "", false
	}

	return device.Status, true
}

// GetDeviceProperties 获取设备属性
func (s *SouthboundService) GetDeviceProperties(deviceID string) (map[string]interface{}, bool) {
	s.devicesLock.RLock()
	device, exists := s.devices[deviceID]
	s.devicesLock.RUnlock()

	if !exists {
		return nil, false
	}

	// 返回属性的副本以避免并发问题
	properties := make(map[string]interface{})
	for k, v := range device.Properties {
		properties[k] = v
	}

	return properties, true
}
